<?php

//打开或获取数据库描述符
function M($file = null, $table = null, $debug = TRUE)
{
    $model = \libs\Model::getInstance($file, $table, $debug);
    return $model;
}

// 异常错误信息输出
function E($mes, $code = 0)
{
    throw new \Exception($mes, $code);
}

//重置错误输出运行代码
function R($call, $echo = FALSE)
{
    set_error_handler(function($no, $str, $file, $line) use($echo) {
        if ($echo)
            printf("%s + %d: (%d)%s\n", $file, $line, $no, $str);
    });

    $ret = $call();

    restore_error_handler();

    return $ret;
}

//执行sql返回数据集
function sqlAll($sql)
{
    return M()->query($sql);
}

//执行sql返回一行数据
function sqlRow($sql)
{
    return M()->query($sql, \libs\Model::ROW);
}

//执行sql返回一列数据
function sqlCol($sql)
{
    return M()->query($sql, \libs\Model::COL);
}

//sql日志输出函数
function sql_log($sql, $title)
{
    $logpath = '/dev/shm/sql.log';
    $log = '';
    if (file_exists($logpath)) {
        $log = file_get_contents('/dev/shm/sql.log');
    }
    $log .= '['.date("Y-m-d H:i:s").'] '.$title.PHP_EOL."\t".$sql.PHP_EOL;
    file_put_contents('/dev/shm/sql.log', $log);
    // exit(0);
}

//获取二级命令
function get_command(& $args)
{
    array_shift($args);
    return array_shift($args);
}

//获取设备文件信息
function get_dev_msg($devfile)
{
    if (!file_exists($devfile))
        E('指定的块设备文件不存在!');

    $out = shell_exec('sudo blkid '.$devfile);
    if ($out === NULL || preg_match_all('/"(.*)"/U', $out, $m) <= 0)
        E($devfile.' 块设备不合法!');

    $uuid = $m[1][0];
    $format = $m[1][1];
    $dsize = rtrim(shell_exec("sudo fdisk -s ".$devfile));
    // printf("uuid = %s, format = %s, size = %s\n", $uuid, $format, $size);

    return compact('uuid', 'format', 'dsize');
}

//自动转换大小，加单位输出
function psize($size, $index = 0, $bit = 1)
{
    while ($size >= 1024) {
        $size /= 1024;
        $index++;
    }

    return round($size, $bit)."BKMGT"[$index];
}

//获取项目ID
function get_pid($name)
{
    $where = ['id' => $name, 'name' => $name];
    $pid = get_data_id('kfm_project', $where);
    $pid === NULL and E('错误：指定的项目不存在!');

    return $pid;
}

//处理命令选项及参数
function kyo_getopt(& $opt, & $args = null)
{
    function _kyo_getopt_args($args)
    {
        if ($args === null) {
            global $argv;
            $args = $argv;
        }
        return $args;
        // 不能去重，去重会影响参数值
        // return array_values(array_unique($args));
    }

    function _kyo_getopt_type($val)
    {
        $type = 0;
        if ($val[0] == ':')
            $type = ($val[1] == ':') ? 2 : 1;

        return $type;
    }

    function _kyo_search_type0($o, & $args)
    {
        $opt = NULL;
        foreach ($args as $key => $arg) {
            if ($o !== $arg)
                continue;
            unset($args[$key]);
            $opt = TRUE;
        }
        return $opt;
    }

    function _kyo_search_type1($o, & $args)
    {
        $opt = null;

        foreach ($args as $key => $arg) {
            if ($o !== $arg) {
                $len = strlen($o) + 1;
                if (!strncmp($o.'=', $arg, $len)) {
                    $opt = substr($arg, $len);
                    unset($args[$key]);
                }
                continue;
            }
            $ind = $key + 1;
            if (! isset($args[$ind]))
                E('选项错误: '.$args[$key].' 选项必须指定参数!');
            $opt = $args[$ind];
            unset($args[$key]);
            unset($args[$ind]);
        }
        return $opt;
    }

    function _kyo_search_type2($o, & $args)
    {
        $opt = NULL;
        foreach ($args as $key => $arg) {
            if (strncmp($o.'=', $arg, strlen($o) + 1)) {
                if ($o === $arg) {
                    unset($args[$key]);
                    $opt = TRUE;
                }
                continue;
            }
            $arrVal = explode('=', $arg);
            if (count($arrVal) == 1)
                E('选项错误: '.$arg.' 可选参数格式错误!');
            unset($args[$key]);
            $opt = $arrVal[1];
        }
        return $opt;
    }

    $args = _kyo_getopt_args($args);
    // print_r($args);

    foreach ($opt as $name => $val) {
        $type = _kyo_getopt_type($val);

        foreach (explode('|', substr($val, $type)) as $o) {
            $v = call_user_func_array('_kyo_search_type'.$type, [$o, & $args]);
            if ($v === NULL)
                continue;
            $opt[$name] = $v;
        }
        // echo $opt[$name], ' # ', $val, PHP_EOL;
        if ($opt[$name] === $val)
            unset($opt[$name]);
    }

    foreach ($args as $arg) {
        if (!strncmp($arg, '-', 1))
            E('选项错误: '.$arg.' 不能识别的选项!');
    }

    return $opt;
}

// 获取数据库记录ID字段
function get_data_id($table, $where)
{
    if (is_array($where)) {
        // where参数为自定义条件，如果是数组则处理组合
        $con = "";
        foreach ($where as $name => $val) {
            // 如果值第一个字符为&代表后面接的操作符为与，否则为或
            if ($val[0] == '&') {
                $opt = 'and';
                $val = substr($val, 1);
            } else {
                $opt = 'or';
            }
            $con .= $name.'="'.$val.'" '.$opt.' ';
        }
        $where = substr($con, 0, -4);
    }

    $sql = 'select id from '.$table.' where '.$where;

    // echo $sql, PHP_EOL;

    return M()->query($sql, \libs\Model::COL);
}

//根据路径获取分区ID(数据库的ID)
function get_disk_id(& $dirname)
{
    $mount = shell_exec("mount | grep '^/dev/' | awk '{print $1,$3}'");
    if ($mount === NULL && strlen($mount) === 0)
        return '错误: 没有找到系统挂载项!';
    $mount = explode("\n", $mount);

    $root_uuid = null;
    $uuid = null;
    foreach ($mount as $line) {
        $dev = explode(' ', $line);
        if (count($dev) != 2)
            continue;

        if ($dev[1] === '/') {
            $cmd = "sudo blkid ".$dev[0]." | awk -F'\"' '{print $2}'";
            $root_uuid = shell_exec($cmd);
            if ($root_uuid === NULL)
                return '错误: 根分区的UUID获取失败!';
            $root_uuid = rtrim($root_uuid);
            continue;
        }

        $len = strlen($dev[1]);
        if (!strncmp($dev[1], $dirname, $len)) {
            $cmd = "sudo blkid ".$dev[0]." | awk -F'\"' '{print $2}'";
            $uuid = shell_exec($cmd);
            if ($uuid === NULL)
                return '错误: '.$dev[0].' 设备获取UUID失败!';
            $uuid = rtrim($uuid);
            $dirname = substr($dirname, $len);
            break;
        }
    }
    if ($uuid === null)
        $uuid = $root_uuid;

    $did = get_data_id('kfm_disk', ['uuid' => $uuid]);
    if ($did === NULL || $did === FALSE)
        return '错误: '.$uuid.' 对应分区在数据库里不存在!';

    return $did;
}

//通过分区ID获取挂载路径
function get_mount_path($id)
{
    $uuid = sqlCol('select uuid from kfm_disk where id='.$id);
    if ($uuid === NULL)
        return '匹配不到对应分区ID!';

    // echo gettype($uuid), ",", $uuid, PHP_EOL;
    $cmd = "mount | grep $(sudo blkid -U ".$uuid.") | awk '{print $3}'";
    $path = shell_exec($cmd);
    if ($path === NULL || $path === FALSE)
        return '分区没有挂载!';
    return rtrim($path);
}

function get_file_tag(& $msg)
{
    $tag = str_replace('/', ',', $msg['dir']).',';

    if (isset($msg['tag'])) {
        if ($msg['tag'][0] == '+')
            $tag .= substr($msg['tag'], 1).',';
        else
            $tag = ','.$msg['tag'].',';
    }
    return $tag;
}

//获取文件信息
function get_file_msg($file, & $data = FALSE)
{
    $msg = $data;

    $path = realpath($file);
    $info = pathinfo($path);
    $msg['did'] = get_disk_id($info['dirname']);
    if (is_string($msg['did']))
        return $msg['did'];
    $msg['dir'] = $info['dirname'];
    $msg['name'] = $info['basename'];
    $msg['md5'] === NULL and $msg['md5'] = md5_file($path);
    $msg['sha1'] = sha1_file($path);
    $msg['tag'] = get_file_tag($msg);
    $msg['mime'] = mime_content_type($path);
    $st = stat($path);
    if ($st === FALSE)
        return '错误: 文件信息获取失败!';
    $msg['size'] = $st['size'];
    $msg['ctime'] = time();
    $msg['atime'] = $st['atime'];
    $msg['mtime'] = $st['mtime'];

    if ($data !== FALSE)
        $data = $msg;

    return $msg;
}


